package program.commands;

import item.*;
import be.kuleuven.cs.som.annotate.*;
import program.conditions.*;

public class WhileLoop extends Commands{
	private final Conditions conditions;
    private final Commands commands;
    
    /**
     * Initialise this new loop with a line number, conditions and commands.
     *
     * @param	conditions
     *      The conditions for executing the loop.
     * @param	commands
     * 		The commands to be executed as long as the condition evaluates to true.
     * @pre	    The given conditions must be valid conditions.
     *          | canHaveAsCondition(conditions)
     * @pre 	The given commands must be valid commands.
     *          | canHaveAsCommand(commands)
     * @post    The conditions of this loop are set to the given conditions.
     *          | new.getConditions() == conditions
     * @post    The commands of this loop are set to the given commands.          
     * 			| new.getCommands() == commands
     */ 
	public WhileLoop(int lineNb, Conditions conditions, Commands commands) {
		super(lineNb);
		assert(canHaveAsConditions(conditions));     
		assert(canHaveAsCommands(commands));
		this.conditions = conditions;
		this.commands = commands;
	}
    
	/**
	 * @return the conditions
	 */
	public Conditions getConditions() {
		return conditions;
	}
	
	/**
	 * @return the commands
	 */
	public Commands getCommands() {
		return commands;
	}
    
	/**
	 * Check whether the given conditions are valid conditions for a loop.
	 *
	 * @param	conditions
	 * 		The conditions to check.
	 * @return      
	 * 		| result == (conditions != null )
	 */
	@Raw
	public boolean canHaveAsConditions(Conditions conditions) {
		return (conditions != null );
	} 

	/**
	 * Check whether the given commands are valid commands for a whileLoop.
	 *
	 * @param	commands
	 *		The commands to check for whether it is a valid one.
	 * @return
	 *		| result == (commands != null )
	 */
	@Raw
	public boolean canHaveAsCommands(Commands commands) {
		return (commands != null );
	} 

	/**
	 * Returns a textual representation of this whileLoop, formatted in accordance with its position in the program.
	 *
	 * @return
	 *		| result == (getIndentation(indentationLevel) + "(while\n" + condition.prettyFormat(indentationLevel+1) + "\n" +
	 *		| 	command.prettyFormat(indentationLevel+1) + getIndentation(indentationLevel) + "\n)" )
	 */
	@Override
	public String prettyFormat(int indentationLevel) {
		return getIndentation(indentationLevel) + "(while\n" + conditions.prettyFormat(indentationLevel+1)
				+ "\n" + commands.prettyFormat(indentationLevel+1) + getIndentation(indentationLevel) + "\n)";
	} 
	
    /**
     * Returns the next basic commands for a robot, given the last executed line number.
     *
     * @return
     *       | if( lineNb >= getLineNb() || !getCondition().evaluate(robot) )
     *       |       then result == null
     * @return
     *       | if( getCommand().getNextBasicCommand(getCondition().getLineNb(), robot) != null )
     *       |       then result == getCommand().getNextBasicCommand(getCondition().getLineNb(), robot)
     * @return
     *       | if( getCommand().getNextBasicCommand(lineNb, robot) == null )
     *       |       then result == getCommand().getNextBasicCommand(getCondition().getLineNb(), robot)
     */
	@Override
	public BasicCommand getNextBasicCommand(int lineNb, Robot robot) {
		if(lineNb >= getLineNb() || !getConditions().evaluate(robot)) return null;
		BasicCommand nextCommand = getCommands().getNextBasicCommand(lineNb, robot);
		if(nextCommand == null)	return getCommands().getNextBasicCommand(getConditions().getLineNb(), robot);
		return nextCommand;
	} 
}
